package com.yonyou.ucf.mdf.app.isvdxq.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.yonyou.iuap.yms.http.*;
import com.yonyou.ucf.mdf.app.isvdxq.ReturnResult.DataResult;
//import org.apache.commons.httpclient.HttpClient;
//import org.apache.commons.httpclient.methods.PostMethod;
//import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.StreamUtils;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

public class RequestTool {
    private static final Logger logger = LoggerFactory.getLogger(RequestTool.class);

    private static final String HEADER_CONTENT_JSON = "application/json";

    private static final String DEFAULT_CHARSET = "UTF-8";

    private static PoolingHttpClientConnectionManager cm = null;

    private static ObjectMapper mapper = new ObjectMapper();

    private static CloseableHttpClient httpClient;

    /**
     * 记录开放平台请求结果
     */
    public static class Response {
        /**
         * 该请求的 http 状态码
         * 200 为正常的返回结果
         */
        private int status;

        /**
         * 请求返回消息
         * 当 status == 200 时会返回 response body 中的字符串
         * 当 status !== 200 时会返回具体的错误信息
         */
        private String result;

        public int getStatus() {
            return status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

        public String getResult() {
            return result;
        }

        public void setResult(String result) {
            this.result = result;
        }
    }

    static {
        cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(500);
        cm.setDefaultMaxPerRoute(50);

        RequestConfig globalConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(1000)         // 连接池获取连接超时
                .setConnectTimeout(1000)                   // 连接建立超时
                .setSocketTimeout(5000)                    // 等待响应超时
                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                .build();

        httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(globalConfig).build();
    }

    private static CloseableHttpClient getHttpClient() {
        return httpClient;
    }

    public static <T> T doGet(String requestUrl, Map<String, String> paramMap, Class<T> type) throws IOException {
        return mapper.readValue(doGet(requestUrl, paramMap), type);
    }

    public static <T> T doGet(String requestUrl, Map<String, String> paramMap, TypeReference<T> typeReference) throws IOException {
        return mapper.readValue(doGet(requestUrl, paramMap), typeReference);
    }

    public static String doGet(String requestUrl, Map<String, String> paramMap) throws IOException {
        CloseableHttpClient httpClient = getHttpClient();
        StringBuilder param = new StringBuilder("?");
        if (requestUrl.contains("?")) param = new StringBuilder("&");
        if (paramMap != null) {
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                param.append(entry.getKey());
                param.append("=");
                param.append(entry.getValue());
                param.append("&");
            }
            param.deleteCharAt(param.length() - 1);
        }
        System.out.println(requestUrl + param);
        HttpGet get = new HttpGet(requestUrl + param);
        String responseString = httpClient.execute(get, response -> EntityUtils.toString(response.getEntity()));
        get.releaseConnection();
        return responseString;
    }

    public static <T> T getBean(String reqString, Class<T> type) throws IOException {
        return mapper.readValue(reqString, type);
    }

    public static <T> T getBean(String reqString, TypeReference<T> typeReference) throws IOException {
        return mapper.readValue(reqString, typeReference);
    }

    public static <T> T doPost(String requestUrl, Map<String, Object> paramMap, Class<T> type) throws IOException {
        return mapper.readValue(doPost(requestUrl, JSON.toJSONString(paramMap)), type);
    }

    public static <T> T doPost(String requestUrl, Map<String, Object> paramMap, TypeReference<T> typeReference) throws IOException {
        return mapper.readValue(doPost(requestUrl, JSON.toJSONString(paramMap)), typeReference);
    }

    /**
     * 模拟POST
     */
//    public static String doPost(String requestUrl, String param) throws IOException {
//        PostMethod poster = new PostMethod(requestUrl);
//        poster.addRequestHeader("Content-Type", "application/json;charset=UTF-8");
//        poster.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
//        poster.setRequestBody(param);
//        HttpClient httpClient = new HttpClient();
//        httpClient.executeMethod(poster);
//        String rst = poster.getResponseBodyAsString();
//        return rst;
//    }


//    public static String doPost(String requestUrl, Map<String, Object> paramMap) throws IOException {
//        PostMethod poster = new PostMethod(requestUrl);
//        poster.addRequestHeader("Content-Type", "application/json;charset=UTF-8");
//        poster.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
//        poster.setRequestBody(JSON.toJSONString(paramMap));
//        HttpClient httpClient = new HttpClient();
//        httpClient.executeMethod(poster);
//        String rst = poster.getResponseBodyAsString();
//        return rst;
//    }

//    public static String doPost(String requestUrl, Map<String, Object> paramMap, Map<String,String> params_headers) throws IOException {
//        PostMethod poster = new PostMethod(requestUrl);
//        poster.addRequestHeader("Content-Type", "application/json;charset=UTF-8");
//        params_headers.forEach((k, v) -> {
//            poster.addRequestHeader(k,v);
//        });
//        poster.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8");
//        poster.setRequestBody(JSON.toJSONString(paramMap));
//        HttpClient httpClient = new HttpClient();
//        httpClient.executeMethod(poster);
//        String rst = poster.getResponseBodyAsString();
//        return rst;
//    }

    private static YmsHttpClient ytsYmsHttpClient = new YmsHttpClient();

    public static String doPost(String requestUrl, String param){
        String response = "";
        YmsHttpHeader ymsHttpHeader = new YmsHttpHeader();
        ymsHttpHeader.add("Content-Type", "application/json;charset=utf-8");
        YmsHttpRequest request = new YmsHttpRequestBuilder().url(requestUrl).method(YmsHttpMethod.POST).body(param).build();
        try {
            YmsHttpResponse ymsHttpResponse= ytsYmsHttpClient.execute(request);
            response = ymsHttpResponse.getBodyString();
        } catch (Exception e) {

        }
        return response;
    }
    public static String doPost(String requestUrl, Map<String, Object> paramMap){
        String response = "";
        String body = JSON.toJSONString(paramMap);
        YmsHttpHeader ymsHttpHeader = new YmsHttpHeader();
        ymsHttpHeader.add("Content-Type", "application/json;charset=utf-8");
        YmsHttpRequest request = new YmsHttpRequestBuilder().url(requestUrl).method(YmsHttpMethod.POST).body(body).build();
        try {
            YmsHttpResponse ymsHttpResponse= ytsYmsHttpClient.execute(request);
            response = ymsHttpResponse.getBodyString();
        } catch (Exception e) {

        }
        return response;
    }
    public static String doPost(String requestUrl, Map<String, Object> paramMap, Map<String,String> params_headers) throws IOException {
        String response = "";
        String body = JSON.toJSONString(paramMap);
        YmsHttpHeader ymsHttpHeader = new YmsHttpHeader();
        ymsHttpHeader.add("Content-Type", "application/json;charset=utf-8");
        params_headers.forEach((k, v) -> {
            ymsHttpHeader.add(k,v);
        });
        YmsHttpRequest request = new YmsHttpRequestBuilder().url(requestUrl).
                method(YmsHttpMethod.POST).body(body).addHeader(ymsHttpHeader).build();
        try (YmsHttpResponse ymsHttpResponse= ytsYmsHttpClient.execute(request)) {
            response = ymsHttpResponse.getBodyString();
        } catch (Exception e) {
            //log.error("The YmsHttp call 'execute' method failed because of the Exception!", e);
        }
        return response;
    }


    /**
     * 从request中获得参数Map，并返回可读的Map
     * 仅支持get参数
     */
    @SuppressWarnings("unchecked")
    public static Map getParameterMap(HttpServletRequest request) {
        // 参数Map
        Map properties = request.getParameterMap();
        // 返回值Map
        Map returnMap = new HashMap();
        Iterator entries = properties.entrySet().iterator();
        Map.Entry entry;
        String name = "";
        String value = "";
        while (entries.hasNext()) {
            entry = (Map.Entry) entries.next();
            name = (String) entry.getKey();
            Object valueObj = entry.getValue();
            if (null == valueObj) {
                value = "";
            } else if (valueObj instanceof String[]) {
                String[] values = (String[]) valueObj;
                for (int i = 0; i < values.length; i++) {
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length() - 1);
            } else {
                value = valueObj.toString();
            }
            returnMap.put(name, value);
        }
        return returnMap;
    }

    /**
     * 读取POST数据流
     */
    public static byte[] readRaw(InputStream inputStream) {
        byte[] result = new byte[1024];
        try {
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];

            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }

            outSteam.close();
            inputStream.close();

            result = outSteam.toByteArray();

        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 完善page参数
     *
     * @param request
     * @param result
     * @return
     * @throws IOException
     */
    public static Map getParamsPage(HttpServletRequest request, DataResult result) throws IOException {
        Map params = getParams(request);
        int pagenum = params.containsKey("pagenum") ? Integer.parseInt(params.get("pagenum").toString()) : 1;
        int pagesize = params.containsKey("pagesize") ? Integer.parseInt(params.get("pagesize").toString()) : 10;
        if (result == null) result = new DataResult();
        result.setPageNum(pagenum);
        result.setPageSize(pagesize);
        return params;
    }

    /**
     * 获取参数Map
     *
     * @param request
     * @return
     * @throws IOException
     */
    public static Map getParams(HttpServletRequest request) {
        // 参数Map
        Map<String, Object> params = null;
        System.out.println("[getParams]" + request.getRequestURI());
        try {
            String contentType = request.getContentType();
            String method = request.getMethod();
            boolean isJsonReq = false;

            // 合并 GET 参数
            String strParam = request.getQueryString();
            if (!StringUtils.isEmpty(strParam)) {
                Map<String, Object> paramsExt = MapUrlParamsUtils.getUrlParams(strParam);
                if (params == null) params = paramsExt;
                else params.putAll(paramsExt);
            }
            // JSON 格式处理
            if (null != contentType && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
                isJsonReq = true;
                Map<String, Object> paramsExt = null;
                ServletInputStream inputStream = request.getInputStream();
                if (inputStream != null) {
                    String myText = IOUtils.toString(inputStream, "UTF-8");
                    if (!StringUtils.isEmpty(myText) && myText.indexOf("=") > 0) {
                        paramsExt = MyTool.paramUrl2Map(myText);
                        isJsonReq = false;
                    } else if (myText.indexOf("{") == 0) {
                        paramsExt = getParamsLast(myText, params);
                    } else {
                        //byte[] requestBody = StreamUtils.copyToByteArray(inputStream);
                        //byte[] requestBody = IOUtils.toByteArray(inputStream);
                        //paramsExt = mapper.readValue(requestBody, HashMap.class);
                    }
                }
                if (paramsExt != null && paramsExt.size() > 0) {
                    if (params == null) params = paramsExt;
                    else params.putAll(paramsExt);
                }
            }
            // text/plain
            else if (null != contentType && contentType.contains(MediaType.TEXT_PLAIN_VALUE)) {
                isJsonReq = true;
                String myText = IOUtils.toString(request.getInputStream(), "UTF-8");
                if (!StringUtils.isEmpty(myText) && myText.indexOf("=") > 0) {
                    myText = MyTool.paramJson(myText);
                    isJsonReq = false;
                }
                if (!StringUtils.isEmpty(myText) && myText.indexOf("{") == 0) {
                    params = getParamsLast(myText, params);
                }
            }
            // text/html
            else if (null != contentType && contentType.contains(MediaType.TEXT_HTML_VALUE)) {
                isJsonReq = true;
                String myText = IOUtils.toString(request.getInputStream(), "UTF-8");
                if (!StringUtils.isEmpty(myText) && myText.indexOf("=") > 0) {
                    myText = MyTool.paramJson(myText);
                    isJsonReq = false;
                }
                if (!StringUtils.isEmpty(myText) && myText.indexOf("{") == 0) {
                    params = getParamsLast(myText, params);
                }
            }
            // application/x-www-form-urlencoded
            else if (null != contentType && contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {

            }
            // multipart/form-data;
            else if (null != contentType && contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {

            }
            if (params == null) params = new HashMap<>();
            logger.warn(isJsonReq + "|" + contentType + "|" + method);
            logger.info("[getParams]" + new Gson().toJson(params));
            System.out.println("[getParams]" + new Gson().toJson(params));
        } catch (Exception ex) {
            logger.info("[getParams]" + ex.getMessage());
            System.out.println("[getParams]" + ex.getMessage());
        }

        return params;
    }

    private static Map<String, Object> getParamsLast(String myText, Map<String, Object> params) {
        Map<String, Object> res = new HashMap<String, Object>();
        try {
            Map<String, Object> paramsExt = JSONObject.parseObject(myText, HashMap.class);
            if (params == null) params = paramsExt;
            else params.putAll(paramsExt);
        } catch (Exception ex) {
            logger.error("[getParamsLast]" + ex.getMessage());
        } finally {
            res = params;
        }
        return res;
    }

    /**
     * 获取数据流对象 或 约定key
     *
     * @param request
     * @return
     * @throws IOException
     */
    public static Map<String, Object> getParamsObject(HttpServletRequest request) throws IOException {
        Map<String, Object> params;
        ObjectMapper mapper = new ObjectMapper();
        String contentType = request.getContentType();
        if (null != contentType && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
            byte[] requestBody = StreamUtils.copyToByteArray(request.getInputStream());
            params = mapper.readValue(requestBody, Map.class);
        } else {
            params = mapper.readValue(request.getParameter("params"), Map.class);
        }

        System.out.println("[getParamsObject]" + new Gson().toJson(params));
        return params;
    }

    public static boolean isJsonReq(HttpServletRequest request) throws IOException {
        String contentType = request.getContentType();
        boolean isJsonReq = false;
        if (null != contentType && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
            isJsonReq = true;
        }
        return isJsonReq;
    }

    /**
     * 获取首个参数值
     *
     * @param request
     * @param key
     * @return
     */
    public static String getHeaderAndParameter(HttpServletRequest request, String key) {
        String result = "";
        String header = request.getHeader(key);
        if (StringUtils.isEmpty(header)) {
            //header = request.getParameter(key);// get 参数
            Map<String, Object> params = new HashMap<>();
            // 合并 GET 参数
            String strParam = request.getQueryString();
            if (!StringUtils.isEmpty(strParam)) {
                Map<String, Object> paramsExt = MapUrlParamsUtils.getUrlParams(strParam);
                if (params == null) params = paramsExt;
                else params.putAll(paramsExt);
            }
            header = params.containsKey(key) ? String.valueOf(params.get(key)) : "";
        }
        if (StringUtils.isNotEmpty(header)) {
            result = header;
        }
        return result;
    }

    /**
     * 获取同key 多个参数值
     *
     * @param request
     * @param key
     * @return
     */
    public static List<String> getHeaderAndParameterList(HttpServletRequest request, String key) {
        List<String> result = new ArrayList<>();
        result = Arrays.asList(request.getParameterValues(key));
        Enumeration<String> headers = request.getHeaders(key);
        while (headers.hasMoreElements()) {
            result.add(headers.nextElement());
        }
        if (result.size() > 1) {
            result = result.stream().filter(it -> StringUtils.isNotEmpty(it)).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 获取请求token
     *
     * @param request
     * @return token
     */
    public static String getToken(HttpServletRequest request)
    {
        String token = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty(token) && token.startsWith("Bearer "))
        {
            token = token.replace("Bearer ", "");
        }
        return token;
    }

    public static Map<String, String> genYHTAccessTokenReqHeader(HttpServletRequest request) {
        Map<String, String> mapHeader = new HashMap<>();
        if (null != request) {
            String yhtAccessToken = findCookieValue(request.getCookies(), "yht_access_token");
            String diworkSessionId = findCookieValue(request.getCookies(), "wb_at");
            mapHeader.put("Cookie", "yht_access_token=" + yhtAccessToken + "; wb_at=" + diworkSessionId);
        }

        return mapHeader;
    }

    /**
     * cookieName = yht_access_token
     * @param cookies
     * @param cookieName
     * @return
     */
    public static String findCookieValue(Cookie[] cookies, String cookieName){
        if (cookies == null) return null;
        Cookie yhtTokenCookie =
                Arrays.stream(cookies)
                        .filter(cookie -> cookieName.equals(cookie.getName()))
                        .findAny()
                        .orElse(null);
        return yhtTokenCookie.getValue();
    }

    /**
     * cookieName = yht_access_token
     * @param request
     * @param response
     * @param cookieName
     * @param yhtAccessToken
     */
    public static void writeCookieToDevice(HttpServletRequest request, HttpServletResponse response, String cookieName, String yhtAccessToken) {
        Cookie cookie = new Cookie(cookieName, yhtAccessToken);
        cookie.setDomain(ClientAddressUtil.getRootDomain(request));
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        response.addCookie(cookie);
    }

    /**
     * 模拟输出
     * @param response
     * @param json
     */
    public static void renderJson(HttpServletResponse response, String json) {
        response.setCharacterEncoding(Consts.UTF_8.name());
        response.setContentType(ContentType.APPLICATION_JSON.getMimeType());
//        response.setContentType("application/json; charset=utf-8");
        try {
            // the max age policy to renew CORS check. Here it's 14 days long
            response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
            response.getWriter().write(json);
        } catch (IOException e) {
            logger.error("exception when render json", e);
        }
    }
    public static void renderHtml(HttpServletResponse response, String html) {
        response.setCharacterEncoding(Consts.UTF_8.name());
        response.setContentType(ContentType.TEXT_HTML.getMimeType());
        try {
            // the max age policy to renew CORS check. Here it's 14 days long
            response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
            response.getWriter().write(html);
        } catch (IOException e) {
            logger.error("exception when render json", e);
        }
    }
}
